﻿using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain.Stores;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Payments;
using Nop.Services.Security;
using Nop.Services.Stores;
using Nop.Web.Framework.Controllers;
using Spotshub.Plugin.Payments.GlobalPayments.Models;
using Spotshub.Plugin.Payments.GlobalPayments.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Nop.Core.Domain.Logging;
using Nop.Core.Domain.Orders;
using Nop.Services.Catalog;
using Nop.Services.Customers;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Telerik.Web.Mvc;

namespace Spotshub.Plugin.Payments.GlobalPayments.Controllers
{
    public class PaymentGlobalPaymentsController : BaseNopPaymentController
    {
        private readonly IRepository<PaymentProfile> _profileRepository;
        private readonly IRepository<PaymentTransaction> _transactionRepository;
        private readonly IRepository<PaymentCreditCard> _creditCardRepository;
        private readonly IRepository<Order> _ordeRepository;
        private readonly ILocalizationService _localizationService;
        private readonly IPermissionService _permissionService;
        private readonly IStoreService _storeService;
        private readonly IGlobalPaymentsService _globalPaymentsService;
        private readonly IPaymentService _paymentService;
        private readonly IWebHelper _webHelper;
        private readonly ISettingService _settingService;
        private readonly GlobalPaymentsSettings _globalPaymentsSettings;
        private readonly ILogger _logger;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly ICustomerService _customerService;
        private readonly IProductService _productService;
        private readonly IWorkflowMessageService _workflowMessageService;
        public PaymentGlobalPaymentsController(
            ILocalizationService localizationService,
            IGenericAttributeService genericAttributeService, IPermissionService permissionService,
            IRepository<PaymentProfile> profileRepository,
            IRepository<PaymentCreditCard> creditCardRepository, IRepository<PaymentTransaction> transactionRepository,
            IRepository<Order> ordeRepository,
            IStoreService storeService,
            IPaymentService paymentService, IGlobalPaymentsService globalPaymentService,
            ISettingService settingService, GlobalPaymentsSettings globalPaymentsSettings,
            IWebHelper webHelper, ILogger logger,
            IOrderProcessingService orderProcessingService, ICustomerService customerService,
            IProductService productService,
            IWorkflowMessageService workflowMessageService)
        {
            this._settingService = settingService;
            this._localizationService = localizationService;
            this._globalPaymentsSettings = globalPaymentsSettings;
            this._permissionService = permissionService;
            this._storeService = storeService;
            this._profileRepository = profileRepository;
            this._transactionRepository = transactionRepository;
            this._creditCardRepository = creditCardRepository;
            this._ordeRepository = ordeRepository;
            this._paymentService = paymentService;
            this._globalPaymentsService = globalPaymentService;
            this._webHelper = webHelper;
            this._logger = logger;
            this._orderProcessingService = orderProcessingService;
            this._customerService = customerService;
            this._productService = productService;
            this._workflowMessageService = workflowMessageService;
        }

        #region Config

        [AdminAuthorize]
        //[ChildActionOnly]
        public ActionResult Configure()
        {
            var model = new ConfigurationModel();
            model.TestUrl = _globalPaymentsSettings.TestIframeUrl;
            model.EnableLog = _globalPaymentsSettings.EnableLog;
            model.EnableDebug = _globalPaymentsSettings.EnableDebug;
            model.AdditionalFee = _globalPaymentsSettings.AdditionalFee;
            model.AdditionalFeePercentage = _globalPaymentsSettings.AdditionalFeePercentage;
            model.FormUrl = _globalPaymentsSettings.FormUrl;
            model.DirectServiceUrl = _globalPaymentsSettings.DirectServiceUrl;
            model.AllowedTypes = _globalPaymentsSettings.AllowedTypes;
            model.AuthorizeEndpoint = _globalPaymentsSettings.AuthorizeEndpoint;
            model.QueryEndpoint = _globalPaymentsSettings.QueryEndpoint;
            model.UIdEndpoint = _globalPaymentsSettings.UIDEndpoint;
            model.CallbackUrl = _globalPaymentsSettings.CallbackUrl;
            model.CssUrl = _globalPaymentsSettings.CssUrl;
            model.EnableSandbox = _globalPaymentsSettings.EnableSandbox;
            model.SandboxAPIToken = _globalPaymentsSettings.SandboxAPIToken;
            model.SandboxProfileId = _globalPaymentsSettings.SandboxProfileId;
            model.SandboxDirectServiceUrl = _globalPaymentsSettings.SandboxDirectServiceUrl;
            model.SandboxFormUrl = _globalPaymentsSettings.SandboxFormUrl;
            model.LogisticsCallbackUrl = _globalPaymentsSettings.LogisticsCallbackUrl;
            model.LogisticsCssUrl = _globalPaymentsSettings.LogisticsCssUrl;
            model.CommerceCallbackUrl = _globalPaymentsSettings.CommerceCallbackUrl;
            model.CommerceCssUrl = _globalPaymentsSettings.CommerceCssUrl;
            model.AppCallbackUrl = _globalPaymentsSettings.AppCallbackUrl;
            model.AppCssUrl = _globalPaymentsSettings.AppCssUrl;
            model.CodeVersion = 1;

            return View(model);
        }

        [HttpPost]
        [AdminAuthorize]
        public ActionResult SaveGeneralSettings(ConfigurationModel model)
        {
            //save settings
            _globalPaymentsSettings.TestIframeUrl = model.TestUrl;
            _globalPaymentsSettings.EnableLog = model.EnableLog;
            _globalPaymentsSettings.EnableDebug = model.EnableDebug;
            _globalPaymentsSettings.AdditionalFee = model.AdditionalFee;
            _globalPaymentsSettings.AdditionalFeePercentage = model.AdditionalFeePercentage;
            _globalPaymentsSettings.FormUrl = model.FormUrl;
            _globalPaymentsSettings.DirectServiceUrl = model.DirectServiceUrl;
            _globalPaymentsSettings.AllowedTypes = model.AllowedTypes;
            _globalPaymentsSettings.AuthorizeEndpoint = model.AuthorizeEndpoint;
            _globalPaymentsSettings.QueryEndpoint = model.QueryEndpoint;
            _globalPaymentsSettings.UIDEndpoint = model.UIdEndpoint;
            _globalPaymentsSettings.CallbackUrl = model.CallbackUrl;
            _globalPaymentsSettings.CssUrl = model.CssUrl;
            _globalPaymentsSettings.EnableSandbox = model.EnableSandbox;
            _globalPaymentsSettings.SandboxAPIToken = model.SandboxAPIToken;
            _globalPaymentsSettings.SandboxProfileId = model.SandboxProfileId;
            _globalPaymentsSettings.SandboxDirectServiceUrl = model.SandboxDirectServiceUrl;
            _globalPaymentsSettings.SandboxFormUrl = model.SandboxFormUrl;
            _globalPaymentsSettings.LogisticsCallbackUrl = model.LogisticsCallbackUrl;
            _globalPaymentsSettings.LogisticsCssUrl = model.LogisticsCssUrl;
            _globalPaymentsSettings.CommerceCallbackUrl = model.CommerceCallbackUrl;
            _globalPaymentsSettings.CommerceCssUrl = model.CommerceCssUrl;
            _globalPaymentsSettings.AppCssUrl = model.AppCssUrl;
            _globalPaymentsSettings.AppCallbackUrl = model.AppCallbackUrl;

            _settingService.SaveSetting(_globalPaymentsSettings);
            return Json(new { Result = true });
        }

        #region Profile Config

        [AdminAuthorize]
        [HttpPost, GridAction]
        public ActionResult ProfileList()
        {
            var profileModel = _profileRepository.Table
                .ToList()
                .Select(x => PrepareProfileModel(x, false))
                .ToList();

            return new JsonResult
            {
                Data = new GridModel<ProfileModel>
                {
                    Data = profileModel,
                    Total = profileModel.Count
                }
            };
        }

        [AdminAuthorize]
        public ActionResult ProfileAdd()
        {
            var model = PrepareProfileModel(null);
            return View(model);
        }

        [AdminAuthorize]
        [HttpPost]
        public ActionResult ProfileAdd(ProfileModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return new HttpUnauthorizedResult();

            var profile = new PaymentProfile();
            profile.ProfileId = model.ProfileId;
            profile.StoreId = model.StoreId;
            profile.ApiToken = model.ApiToken;
            profile.Type = model.Type;

            _profileRepository.Insert(ToProfileEntity(model));

            ViewBag.RefreshPage = true;
            return View(model);
        }

        [AdminAuthorize]
        public ActionResult ProfileEdit(int id)
        {
            var profile = _profileRepository.GetById(id);
            var model = PrepareProfileModel(profile);
            return View(model);
        }

        [AdminAuthorize]
        [HttpPost]
        public ActionResult ProfileEdit(ProfileModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
                return new HttpUnauthorizedResult();

            var profile = _profileRepository.GetById(model.Id);
            profile.ProfileId = model.ProfileId;
            profile.StoreId = model.StoreId;
            profile.ApiToken = model.ApiToken;
            profile.Type = model.Type;

            _profileRepository.Update(ToProfileEntity(model));

            ViewBag.RefreshPage = true;
            return View(model);
        }

        [AdminAuthorize]
        [HttpPost, GridAction]
        public ActionResult ProfileDelete(int id)
        {
            var profile = _profileRepository.GetById(id);
            if (profile != null)
                _profileRepository.Delete(profile);
            return ProfileList();
        }

        #endregion

        #endregion

        protected List<ShoppingCartItem> GetCart(int customerId)
        {
            //_workContext.CurrentCustomer.Id = userId;

            var customer = _customerService.GetCustomerById(customerId);
            var cart = customer.ShoppingCartItems.Where(x => x.ShoppingCartTypeId == 1).ToList();

            //return _workContext.CurrentCustomer.ShoppingCartItems
            //    .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
            //    .ToList();
            return cart;
        }
        private int GetCerateOrderId(int useId)
        {
            var cart = GetCart(useId);
            var storeOrder = _storeService.GetStoreShoppingCartItems(cart);
            storeOrder.ProcessPaymentRequest.CustomerId = useId;
            var order = _orderProcessingService.PlaceOrder(storeOrder, true);
            if (order.PlacedOrders != null && order.PlacedOrders.Count > 0)
            {
                return order.PlacedOrders[0].Id;
            }

            return 0;
        }

        [ValidateInput(false)]
        public ActionResult HandleTransaction()
        {
            try
            {
                //authorize callback request
                //if (!processor.VerifyMessageAuthentication(Request.Headers))
                //{
                //    return new HttpStatusCodeResult(401, "Access Denied");
                //}

                Helper.FileLog(
                    "HandleTransaction",
                    Helper.GetHeaderString(Request.Headers, Request.HttpMethod),
                    _globalPaymentsSettings.EnableLog);

                //parse transaction
                string xmlData = "";

                if (_globalPaymentsSettings.EnableDebug)
                {
                    var sample = _globalPaymentsSettings.SampleResponse;
                    if (!String.IsNullOrWhiteSpace(sample))
                    {
                        xmlData = Helper.GetSampleFileContent(sample);
                    }
                }
                else
                {
                    var requestStream = Request.InputStream;
                    using (var requestStreamReader = new StreamReader(requestStream))
                        xmlData = requestStreamReader.ReadToEnd();

                    Helper.FileLog(
                        "HandleTransaction",
                        xmlData,
                        _globalPaymentsSettings.EnableLog);
                }
                _logger.InsertLog(LogLevel.Information, "update order paymentStatus", xmlData);
                var transaction = XmlHelper.Deserialize<transaction>(xmlData);

                //    //TODO: verify necessary fields.
                Helper.FileLog(
                 "HandleTransaction",
                    "transactionMessage",
                 _globalPaymentsSettings.EnableLog);

                var profile = new PaymentProfile();
                if (_globalPaymentsSettings.EnableSandbox)
                {
                    // Hard coded store id, sandbox testing purpose only
                    profile = _profileRepository.Table.FirstOrDefault(p => p.Id == 1);
                }
                else
                {
                    profile = _profileRepository.Table.FirstOrDefault(p => p.ProfileId == transaction.merchantPass);
                }
                Helper.FileLog(
                "HandleTransaction",
                   "transactionprofile:" + profile.ProfileId,
                _globalPaymentsSettings.EnableLog);
                #region add CreditCard
                if (transaction != null && !string.IsNullOrEmpty(transaction.tokenId))
                {
					int customerId = string.IsNullOrEmpty(transaction.customerId)
                        ? 0
                        : int.Parse(transaction.customerId);
                    int expMonth = transaction.expMonth ?? 0;
                    int expYear = transaction.expYear ?? 0;
                    string creditCardName = transaction.name;
                    string creditCardNumber = transaction.cardNumber;

					Helper.FileLog(
			  "HandleTransaction",
				 "creditCardName:" + creditCardName + "   card number:" + creditCardNumber + "customerId:" + customerId,
			  _globalPaymentsSettings.EnableLog);

                    #region 判断Cartd 是否已经存在

					var creditCard = _creditCardRepository.Table.FirstOrDefault(c => c.CustomerId == customerId
                                                                                     &&
                                                                                     c.CreditCardExpireMonth == expMonth
                                                                                     &&
                                                                                     c.CreditCardExpireYear == expYear
                                                                                     &&
                                                                                     c.CreditCardName == creditCardName
                                                                                     &&
                                                                                     c.CreditCardNumber == creditCardNumber
                                                                                     &&
                                                                                     c.PaymentProfileId == profile.Id);
                    if (creditCard != null)
                    {
                        Helper.FileLog(
                        "HandleTransaction",
                        "creditCard is not null",
                        _globalPaymentsSettings.EnableLog);
                        return new EmptyResult();
                    }

                    #endregion

                    var cc = new PaymentCreditCard();
                    if (profile.Id > 0)
                    {
                        cc.CreditCardExpireMonth = expMonth;
                        cc.CreditCardExpireYear = expYear;
                        cc.CreditCardName = creditCardName;
                        cc.CreditCardNumber = creditCardNumber;
                        cc.CreditCardType = transaction.cardType;
						cc.CustomerId = customerId;
                        cc.Token = transaction.tokenId;
                        cc.PaymentProfileId = profile.Id;
                        cc.RawResult = xmlData;
                        _creditCardRepository.Insert(cc);
                    }
                    Helper.FileLog(
                    "HandleTransaction",
                    "creditCard is null",
                    _globalPaymentsSettings.EnableLog);
                }
                #endregion
                #region app pay
                if (transaction != null && string.IsNullOrEmpty(transaction.tokenId) && string.IsNullOrEmpty(transaction.orderId))
                {
                    Helper.FileLog(
                        "HandleTransaction",
                        "uID:" + transaction.uID + ",profileStoreId:" + profile.StoreId + "profileId:" + profile.ProfileId + ",ApiToken:" + profile.ApiToken,
                        _globalPaymentsSettings.EnableLog);

                    int orderId = GetOrderId(transaction.uID, profile, transaction);
                    Helper.FileLog(
                      "HandleTransaction",
                      "orderId=" + orderId,
                      _globalPaymentsSettings.EnableLog);

                    if (orderId == 0)
                    {
                        return new EmptyResult();
                    }
                    _transactionRepository.Insert(new PaymentTransaction()
                      {
                          CreateOnUtc = DateTime.UtcNow,
                          RawResult = xmlData,
                          Amount = string.IsNullOrEmpty(transaction.amount) ? 0m : Convert.ToDecimal(transaction.amount),
                          CreditCardId = 0,
                          OrderId = orderId,
                          PaymentStatus = Nop.Core.Domain.Payments.PaymentStatus.Paid,
                          UId = transaction.uID
                      });
                    Helper.FileLog(
                       "HandleTransaction",
                       "Transaction insert success",
                       _globalPaymentsSettings.EnableLog);
                    var getOneOrder = _ordeRepository.Table.FirstOrDefault(o => o.Id == orderId);
                    if (getOneOrder != null)
                    {
                        updatePaySuccessOrder(getOneOrder);
                        Helper.FileLog(
                      "HandleTransaction",
                      "update success",
                      _globalPaymentsSettings.EnableLog);
                    }
                }
                #endregion
            }
            catch (Exception exc)
            {
				 Helper.FileLog(
                       "HandleTransaction",
					   "Error:"+exc.Message+"\r\nStack:"+exc.StackTrace,
						_globalPaymentsSettings.EnableLog);

                _logger.Error("Fatal errors in the HandleTransaction", exc);
            }
            return new EmptyResult();
        }

        private void updatePaySuccessOrder(Order order)
        {
            order.PaymentStatus = Nop.Core.Domain.Payments.PaymentStatus.Paid;
            _ordeRepository.Update(order);
            //修改库存
            foreach (var productVarant in order.OrderProductVariants)
            {
                _productService.AdjustInventory(productVarant.ProductVariant, true, productVarant.Quantity, productVarant.AttributesXml);
            }
            //发送邮件
            int orderPlacedCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderPlacedCustomerNotification(order, order.CustomerLanguageId);
            if (orderPlacedCustomerNotificationQueuedEmailId <= 0)
            {
                _logger.Error("add email errors orderId:" + order.Id);
            }
        }

        private void PayOrder(int creditCardId, decimal amount, int orderId)
        {
            var pay = _globalPaymentsService.RepeatSale(creditCardId, amount, orderId.ToString());
            if (pay.Success)
            {
                var oneorder = _ordeRepository.Table.FirstOrDefault(o => o.Id == orderId);
                //修改订单状态
                if (oneorder != null)
                {
                    updatePaySuccessOrder(oneorder);
                }
            }
        }

        private int GetOrderId(string UId, PaymentProfile profile, transaction transaction)
        {
            var orderId = 0;
            var isUId = _transactionRepository.Table.SingleOrDefault(p => p.UId == UId);
            if (isUId == null && profile != null)
            {

                try
                {
                    using (WebClient wc = new WebClient())
                    {
                        var url = _settingService.GetSettingByKey("globalpaymentssettings.gtpaysecureurl").Value;
                        url = string.Format(url, profile.ProfileId, profile.ApiToken, transaction.uID);
                        var res = wc.UploadString(url, "POST", "");
                        foreach (var oneres in res.Split('&'))
                        {
                            if (oneres.IndexOf("=", StringComparison.Ordinal) != -1 && oneres.Contains("order_id"))
                            {

                                transaction.orderId = oneres.Split('=')[1];
                            }
                        }
                    }
                    if (!string.IsNullOrEmpty(transaction.orderId))
                    {
                        orderId = int.Parse(transaction.orderId);
                    }
                }
                catch (Exception exc)
                {
                    _logger.InsertLog(LogLevel.Error, exc.Message);
                    return orderId;
                }
            }
            return orderId;
        }

        //[HttpPost]
        //public ActionResult TransactionCompleted(int storeId, int customerId, string uID)
        //{
        //    //var model = new PaymentInfoModel();
        //    //model.SessionId = transaction.sessionId;
        //    //var partialView = this.RenderPartialViewToString("Spotshub.Plugin.Payments.GlobalPayments.Views.PaymentGlobalPayments._SuccessNotification", model);

        //    var res = _globalPaymentsService.GetCardOnFileResult(storeId, uID);

        //    if (!res.Succeeded)
        //    {
        //    }

        //    var cc = _globalPaymentsService.SaveCreditCard(res, customerId, storeId);
        //    return Json(cc.Id);
        //}


        #region Payment Form

        [ChildActionOnly]
        public ActionResult PaymentInfo(int customerId, int storeId, int? creditCardId, string returnRouteName, string type = "")
        {

            Helper.FileLog(
                   "PaymentInfo",
                   Helper.GetHeaderString(Request.Headers, Request.HttpMethod),
                   _globalPaymentsSettings.EnableLog);

            int creditCardIdInt = creditCardId == null ? 0 : creditCardId.Value;

            Helper.FileLog(
             "PaymentInfo",
             "customerId:" + customerId + ",storeId:" + storeId + ",creditCardId:" + creditCardIdInt.ToString() + "returnRouteName:" + returnRouteName + "type:" + type,
             _globalPaymentsSettings.EnableLog);
            var model = new PaymentInfoModel()
            {
                DebugEnabled = _globalPaymentsSettings.EnableDebug,
                CustomerId = customerId,
                IsOnePageCheckout = _globalPaymentsService.UseOnePageCheckout(),
                StoreId = storeId,
                ReturnRouteName = returnRouteName
            };
            Helper.FileLog(
            "PaymentInfo",
            "customerId:" + customerId.ToString() + ",storeId:" + storeId,
            _globalPaymentsSettings.EnableLog);

            var ccs = _globalPaymentsService.GetCreditCardsByCustomer(customerId, storeId);
            if (ccs.Count > 0)
            {
                /*
                model.CreditCards = ccs
                    .Select(c => new SelectListItem
                    {
                        Value = c.Id.ToString(),
                        Text = String.Format("{0} {1} {2} {3}/{4}", c.CreditCardType, c.CreditCardNumber, c.CreditCardName, c.CreditCardExpireMonth, c.CreditCardExpireYear),
                        Selected = c.IsDefault
                    }).ToList();
                 */
                model.CreditCards = ccs.Select(c => new PaymentInfoModel.CreditCard()
                {
                    Id = c.Id,
                    Type = c.CreditCardType,
                    Number = c.CreditCardNumber,
                    Name = c.CreditCardName,
                    ExpiryMonth = c.CreditCardExpireMonth,
                    ExpiryYear = c.CreditCardExpireYear,
                    IsDefault = c.IsDefault
                }).ToList();
                model.ShowCreditCards = true;
                model.ShowForm = false;
                if (creditCardId.HasValue && creditCardId > 0)
                    model.CreditCardId = creditCardId.Value;
            }
            else
            {

                if (model.DebugEnabled && !String.IsNullOrEmpty(_globalPaymentsSettings.TestIframeUrl))
                {
                    Helper.FileLog(
                    "PaymentInfo",
                    "TestIframeUrl:" + _globalPaymentsSettings.TestIframeUrl,
                    _globalPaymentsSettings.EnableLog);
                    model.SecureFormUrl = _globalPaymentsSettings.TestIframeUrl;
                }
                else
                {


                    var res = _globalPaymentsService.GetCardOnFileFormUrl(customerId, storeId, type);


                    if (!res.Success)
                    {


                        model.Warnings.AddRange(res.Errors);
                        Helper.FileLog(
                         "PaymentInfo",
                         "FileFormUrlerrors" + model.Warnings.ToList(),
                         _globalPaymentsSettings.EnableLog);
                    }
                    else
                    {
                        Helper.FileLog(
                         "PaymentInfo",
                         "Success FileFormUrl:" + res + "UID:" + res.UID,
                         _globalPaymentsSettings.EnableLog);

                        model.SecureFormUrl = res.URL;
                        model.UID = res.UID;
                    }
                }
                model.ShowCreditCards = false;
                model.ShowForm = true;
            }

            return View(model);
        }

        [HttpPost]
        public JsonResult GetSecureFormUrl(int customerId, int storeId, string type = "")
        {
            string url;
            string uid;

            if (_globalPaymentsSettings.EnableDebug && !String.IsNullOrEmpty(_globalPaymentsSettings.TestIframeUrl))
            {
                url = _globalPaymentsSettings.TestIframeUrl;
                uid = "";
            }
            else
            {
                var res = _globalPaymentsService.GetCardOnFileFormUrl(customerId, storeId, type);

                if (!res.Success)
                {
                    return Json(new
                    {
                        success = false,
                        errors = String.Join(" ", res.Errors)
                    });
                }

                url = res.URL;
                uid = res.UID;
            }

            return Json(new
            {
                success = true,
                url = url,
                uid = uid
            });
        }


        [HttpPost]
        public JsonResult SaveCreditCard(int customerId, int storeId, string uid)
        {

            Helper.FileLog(
            "SaveCreditCard",
            "customerId:" + customerId.ToString() + "storeId:" + storeId.ToString() + "uid:" + uid,
            _globalPaymentsSettings.EnableLog);

            var res = _globalPaymentsService.SaveCreditCard(customerId, storeId, uid);
            if (res.Success)
            {
                return Json(new
                {
                    success = true,
                    creditCardId = res.CreditCardId
                });
            }

            return Json(new
            {
                success = false,
                errors = String.Join(" ", res.Errors)
            });
        }

        [HttpPost]
        public JsonResult RemoveCreditCard(int customerId, int storeId, int creditCardId)
        {
            var cc = _creditCardRepository.GetById(creditCardId);
            if (cc == null || cc.CustomerId != customerId)
            {
                return Json(new
                {
                    success = false,
                    errors = "Unable to delete this credit card. It either does not exist, or you are not authorized to manage it."
                });
            }
            _creditCardRepository.Delete(cc);
            return Json(new
            {
                success = true,
                errors = "Credit card has been deleted successfully."
            });
        }

        //[HttpPost]
        //public ActionResult PaymentInfoGetCCInfo(int storeId, int customerId, string uID)
        //{
        //    var res = _globalPaymentsService.GetCardOnFileResult(storeId, uID);

        //    if (res.Succeeded)
        //    {
        //        // Saving new card
        //        var cc = _globalPaymentsService.SaveCreditCard(res, customerId, storeId);

        //        return new JsonResult()
        //        {
        //            Data = new
        //            {
        //                succeeded = true,
        //                card = cc.Id
        //            }
        //        };
        //    }

        //    return new JsonResult()
        //    {
        //        Data = new
        //        {
        //            succeeded = false,
        //            error = String.Join("\n\r", res.Errors)
        //        }
        //    };
        //}

        [NonAction]
        public override IList<string> ValidatePaymentForm(FormCollection form)
        {
            var warnings = new List<string>();

            if (form == null)
            {
                warnings.Add("The collection is empty.");
                return warnings;
            }

            int storeId = 0;
            //int customerId = 0;
            int creditCardId = 0;

            if (!int.TryParse(form["StoreId"], out storeId))
            {
                warnings.Add("The store ID is missing.");
            }
            else if (_storeService.GetStoreById(storeId) == null)
            {
                warnings.Add(String.Format("The store ID {0} is missing", storeId));
            }

            //if (!int.TryParse(form["CustomerId"], out customerId))
            //{
            //    errors.Add("The customer ID is missing.");
            //}

            if (!int.TryParse(form["CreditCardId"], out creditCardId))
            {
				if(String.IsNullOrEmpty(form["newCard"]))
					warnings.Add("The credit card ID is missing.");
            }
            else if (_creditCardRepository.GetById(creditCardId) == null)
            {
                warnings.Add(String.Format("The credit card ID {0} is invalid.", creditCardId));
            }

            return warnings;

            // Validate postback values
            //string uID = "";
            //int customerId = 0;
            //int storeId = 0;

            //int selectedCardId = 0;
            //PaymentCreditCard cc = null;

            //if (selectedCardId == 0)
            //{
            //    // Saving new card
            //    var res = processor.GetCardOnFileResult(storeId, uID);

            //    if (!res.Succeeded)
            //    {
            //    }

            //    cc = processor.SaveCreditCard(res, customerId, storeId);
            //}
            //else
            //{
            //    // Selected existing
            //    cc = processor.GetCreditCardById(customerId, storeId, selectedCardId);
            //}



            //var strSessionId = form[GlobalPaymentsProcessor.SessionIdKeyName];

            //if (String.IsNullOrWhiteSpace(strSessionId))
            //{
            //    warnings.Add("Session ID does not exist or it is empty.");
            //    return warnings;
            //}

            ////int creditCardId = form.GetValue(GlobalPaymentsProcessor.SelectedCreditCardKeyName)
            ////if (String.IsNullOrWhiteSpace(creditCard))
            ////{
            ////    warnings.Add("Session ID does not exist or it is empty.");
            ////    return warnings;
            ////}

            //string uID = form["uid"];
            //int storeId = 0;
            //int customerId = 0;

            //var res = processor.GetCardOnFileResult(storeId, uID);

            //if (res.Succeeded)
            //{
            //    var cc = processor.SaveCreditCard(res, customerId, storeId);
            //}

            //Guid sessionId;

            //if (Guid.TryParse(strSessionId, out sessionId) == false)
            //{
            //    warnings.Add(String.Format("Session ID {0} is invalid.", strSessionId));
            //}

        }

        [NonAction]
        public override ProcessPaymentRequest GetPaymentInfo(FormCollection form)
        {
            var paymentInfo = new ProcessPaymentRequest();

            PaymentCreditCard cc = null;

            int creditCardId = int.Parse(form["CreditCardId"]);

            // Selected existing
            cc = _globalPaymentsService.GetCreditCardById(creditCardId);
            paymentInfo.CustomerId = cc.CustomerId;
            paymentInfo.CustomValues[CustomValues.CreditCardId] = creditCardId;
            paymentInfo.StoreId = int.Parse(form["StoreId"]);
            //paymentInfo.TransactionId = cc.Id.ToString();
            paymentInfo.CreditCardId = creditCardId;
            paymentInfo.CreditCardNumber = cc.CreditCardNumber;
            paymentInfo.CreditCardName = cc.CreditCardName;
            paymentInfo.CreditCardExpireMonth = cc.CreditCardExpireMonth;
            paymentInfo.CreditCardExpireYear = cc.CreditCardExpireYear;
            paymentInfo.CreditCardType = cc.CreditCardType;

            return paymentInfo;
        }

        #endregion

        #region Helper

        [NonAction]
        protected ProfileModel PrepareProfileModel(PaymentProfile profile, bool prepareStoreList = true)
        {
            var model = new ProfileModel();
            if (profile != null)
            {
                var store = _storeService.GetStoreById(profile.StoreId);
                model.Id = profile.Id;
                model.ApiToken = profile.ApiToken;
                model.ProfileId = profile.ProfileId;
                model.Store = store == null ? "Error" : store.Name;
                model.StoreId = profile.StoreId;
                model.Type = profile.Type;
            }

            if (prepareStoreList)
            {

                model.AvailableStores = GetAvaliableStores()
                    .Select(x => new SelectListItem() { Selected = x.Id == (profile == null ? 0 : profile.StoreId), Text = x.Name, Value = x.Id.ToString() })
                    .ToList();

                model.AvailableStores.Insert(0, new SelectListItem() { Selected = (profile == null ? 0 : profile.StoreId) == Store.AllStoreReservedId, Value = Store.AllStoreReservedId.ToString(), Text = "Default" });
            }
            return model;
        }

        [NonAction]
        protected PaymentProfile ToProfileEntity(ProfileModel model)
        {
            return new PaymentProfile()
            {
                StoreId = model.StoreId,
                ApiToken = model.ApiToken,
                Type = model.Type,
                ProfileId = model.ProfileId
            };
        }

        [NonAction]
        protected IList<Store> GetAvaliableStores()
        {
            var stores = _storeService.GetAllStores();
            var storeIdsWithProfile = _profileRepository.Table.Select(x => x.StoreId).ToList();

            var avaliableStores = new List<Store>();

            foreach (var store in stores)
            {
                if (!storeIdsWithProfile.Any(x => x == store.Id))
                {
                    avaliableStores.Add(store);
                }
            }

            return avaliableStores;
        }

        [NonAction]
        protected IList<string> TryGetFormValues(FormCollection form, out int storeId, out int customerId, out int creditCardId)
        {
            var errors = new List<string>();

            storeId = 0;
            customerId = 0;
            creditCardId = 0;

            if (!int.TryParse(form["StoreId"], out storeId))
            {
                errors.Add("The store ID is missing.");
            }
            else if (_storeService.GetStoreById(storeId) == null)
            {
                errors.Add(String.Format("The store ID {0} is missing", storeId));
            }

            //if (!int.TryParse(form["CustomerId"], out customerId))
            //{
            //    errors.Add("The customer ID is missing.");
            //}

            if (!int.TryParse(form["CreditCard"], out creditCardId))
            {
                errors.Add("The credit card ID is missing.");
            }
            else if (_creditCardRepository.GetById(creditCardId) == null)
            {
                errors.Add(String.Format("The credit card ID {0} is invalid.", creditCardId));
            }

            return errors;
        }

        #endregion
    }
}